﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Globalization;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using HQPad.Models;
using HQPad.Services;

namespace HQPad.Controllers
{
    public class InvocationController : BaseController
    {
        private HQContext context = new HQContext();

        //
        // GET: /Invocation/

        public ViewResult Index(int? id, string sphere, string guild)
        {
            IRulesService rulesService = new RulesService(context);
            IInvocationService invocationService = new InvocationService(context);
            IGuildService guildService = new GuildService(context);

            if (!id.HasValue)
                id = rulesService.GetDefaultRules().RuleSetID;

            RuleSet rules = rulesService.GetRules(id.Value);
            PopulateRuleVersion(rules);

            PopulateSpheres(null, false);

            IEnumerable<Invocation> invocations = invocationService.GetInvocations(id.Value);

            // Get all guilds used
            List<Guild> guilds = guildService.GetGuildsWithInvocations(rules.RuleSetID).ToList();

            ViewBag.Guild = new SelectList(guilds, "Slug", "Name", guild != null && guild != "All" ? guild : "All");

            // Do any filters.
            if (sphere != null && sphere != "All")
                invocations = invocations.Where(i => i.Sphere.ToLower() == sphere.ToLower());

            if (guild != null && guild != "All")
                invocations = invocations.Where(i => i.Guilds.Select(g => g.Slug).Contains(guild));

            // order by sphere, family and level.
            invocations = invocations.OrderBy(i => i.Sphere).ThenBy(i => i.Family).ThenBy(i => i.Rank);

            return View(invocations.ToList());
        }

        //
        // GET: /Invocation/Create

        public ActionResult Create(int? ruleSetId)
        {
            IRulesService rulesService = new RulesService(context);
            
            PopulateSpheres(null);
            PopulateInvocationRanks(null);

            if (!ruleSetId.HasValue)
                ruleSetId = rulesService.GetDefaultRules().RuleSetID;

            RuleSet rules = rulesService.GetRules(ruleSetId.Value);
            PopulateRuleVersion(rules);

            return View();
        } 

        //
        // POST: /Invocation/Create

        [HttpPost]
        public ActionResult Create(Invocation invocation, FormCollection formCollection)
        {
            IInvocationService invocationService = new InvocationService(context);
            IRulesService rulesService = new RulesService(context);

            string invocationSphere = formCollection["Sphere"];
            ModelState.SetModelValue("Sphere", new ValueProviderResult(invocationSphere, invocationSphere, new CultureInfo("en-GB")));

            string rank = formCollection["Rank"];
            ModelState.SetModelValue("Rank", new ValueProviderResult(rank, rank, new CultureInfo("en-GB")));

            invocation.Deleted = false;
            invocation.LastUpdated = DateTime.Now;
            invocation.LastUpdatedByUserID = 1;

            // Create a invocation slug from the invocation name.
            string slug = invocationService.CreateInvocationSlug(invocation.Name);

            // Try and get a invocation with this slug to check for uniqueness.
            Invocation existingInvocation = invocationService.GetInvocation(invocation.RuleSetID, slug);

            if (existingInvocation != null)
            {
                ModelState.AddModelError("Slug", string.Format("Unable to save changes. The generated invocation slug {0} already exists in the system, try a different invocation name.", slug));
            }
            else
            {
                ModelState.SetModelValue("Slug", new ValueProviderResult(slug, slug, new CultureInfo("en-GB")));
                invocation.Slug = slug;
                ModelState["Slug"].Errors.Clear();
            }

            TryUpdateModel(invocation);


            if (ModelState.IsValid)
            {
                invocationService.Add(invocation);
                context.Save();
                return RedirectToAction("Index");  
            }
            RuleSet rules = rulesService.GetRules(invocation.RuleSetID);
            PopulateRuleVersion(rules);

            return View(invocation);
        }
        
        //
        // GET: /Invocation/Edit/5
 
        public ActionResult Edit(int? ruleSetId, string slug)
        {
            IInvocationService invocationService = new InvocationService(context);
            IRulesService rulesService = new RulesService(context);

            if (ruleSetId.HasValue)
            {
                RuleSet rules = rulesService.GetRules(ruleSetId.Value);
                PopulateRuleVersion(rules);
            }

            Invocation invocation = invocationService.GetInvocation(ruleSetId.Value, slug);

            PopulateSpheres(invocation.Sphere);
            PopulateInvocationRanks(invocation.Rank);
            PopulateAvailableGuilds(invocation);

            return View(invocation);
        }

        //
        // POST: /Invocation/Edit/5

        [HttpPost]
        public ActionResult Edit(Invocation invocation)
        {
            IRulesService rulesService = new RulesService(context);

            invocation.LastUpdated = DateTime.Now;
            invocation.LastUpdatedByUserID = 1; // todo: Add current user id.

            if (ModelState.IsValid)
            {
                IInvocationService invocationService = new InvocationService(context);

                invocationService.UpdateInvocation(invocation);

                context.Save();

                return RedirectToAction("Index");
            }

            PopulateSpheres(invocation.Sphere);
            PopulateInvocationRanks(invocation.Rank);
            PopulateAvailableGuilds(invocation);

            RuleSet rules = rulesService.GetRules(invocation.RuleSetID);
            PopulateRuleVersion(rules);

            return View(invocation);
        }

        ////
        //// GET: /Invocation/Delete/5

        public ActionResult Delete(int ruleSetId, string slug)
        {
            IInvocationService invocationService = new InvocationService(context);
            Invocation invocation = invocationService.GetInvocation(ruleSetId, slug);

            if (invocation != null)
            {
                invocationService.DeleteInvocation(invocation.InvocationID);
                context.Save();
            }

            return RedirectToAction("Index", new { id = ruleSetId });
        }

        public ActionResult AddGuild(int ruleSetId, string slug)
        {
            int guildId = 0;

            string guild = Request.Form["Guilds"];

            if (guild != null && int.TryParse(guild, out guildId))
            {
                IGuildService guildService = new GuildService(context);

                Guild guildToAdd = guildService.GetGuild(guildId);

                if (guildId != null)
                {

                    IInvocationService invocationService = new InvocationService(context);

                    Invocation parentInvocation = invocationService.GetInvocation(ruleSetId, slug);

                    if (parentInvocation.Guilds == null)
                        parentInvocation.Guilds = new List<Guild>();

                    parentInvocation.Guilds.Add(guildToAdd);

                    context.Save();
                }
            }

            return RedirectToAction("edit", new { slug = slug });
        }

        public ActionResult DeleteGuild(int id, string slug, int ruleSetId)
        {
            IInvocationService invocationService = new InvocationService(context);

            Invocation parentInvocation = invocationService.GetInvocation(ruleSetId, slug);

            if (parentInvocation.Guilds != null)
            {
                Guild guild = parentInvocation.Guilds.Where(g => g.GuildID == id).FirstOrDefault();

                if (guild != null)
                {
                    parentInvocation.Guilds.Remove(guild);
                    context.Save();
                }
            }

            return RedirectToAction("edit", new { slug = slug });
        }

        protected override void Dispose(bool disposing)
        {
            context.Dispose();
            base.Dispose(disposing);
        }

        protected void PopulateSpheres(string selectedSphere, bool addAll = false)
        {
            List<string> spheres = Enum.GetNames(typeof(Sphere)).ToList();

            if (addAll)
                spheres.Insert(0, "All");

            ViewBag.Sphere = new SelectList(spheres, selectedSphere);
        }

        protected void PopulateInvocationRanks(int? selectedRank)
        {
            ViewBag.Rank = new SelectList(new int[10] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }, selectedRank.HasValue ? selectedRank.Value : 0);
        }

        protected void PopulateAvailableGuilds(Invocation invocation)
        {
            IGuildService guildService = new GuildService(context);

            IEnumerable<int> assignedGuildIds = invocation.Guilds.Select(g => g.GuildID);

            IEnumerable<Guild> availableGuilds = 
                guildService.GetGuilds(invocation.RuleSetID)
                .Where(g => !assignedGuildIds.Contains(g.GuildID));

            ViewBag.Guilds = new SelectList(availableGuilds, "GuildID", "Name");
        }
    }
}